#include "driver.h"

#define GET_PFAST_IO_DISPATCH ((PDD_DEVICE)DeviceObject->DeviceExtension)->	\
	FileSystem->															\
	DriverObject->															\
	FastIoDispatch													

#define GET_PFAST_IO_DISPATCH2 doit(FileObject)




#define GET_FAST_IO_DISPATCH(devExt) (((PDD_DEVICE)devExt)->FileSystem->DriverObject->FastIoDispatch)

#define FAST_IO_PRESENT(devExt, Method)										\
	(!(devExt)->GuiInterface &&												\
	GET_FAST_IO_DISPATCH(devExt) != NULL &&									\
	(ULONG) &GET_FAST_IO_DISPATCH(devExt)->Method -							\
	(ULONG) &GET_FAST_IO_DISPATCH(devExt)->SizeOfFastIoDispatch <			\
	(ULONG) GET_FAST_IO_DISPATCH(devExt)->SizeOfFastIoDispatch)

PFAST_IO_DISPATCH doit(IN PFILE_OBJECT FileObject) 
{
	PDEVICE_OBJECT DeviceObject;
	for (
		DeviceObject = FileObject->DeviceObject->Vpb->DeviceObject;
		DeviceObject;
	DeviceObject = DeviceObject->AttachedDevice) 
	{
		DbgMess(("Some FastIo Starts"));

		if (DeviceObject->DriverObject == DDDriverObject)
			return GET_PFAST_IO_DISPATCH;
	}
	return 0;
}


BOOLEAN
DDFastIoCheckifPossible (
						 IN struct _FILE_OBJECT *FileObject,
						 IN PLARGE_INTEGER FileOffset,
						 IN ULONG Length,
						 IN BOOLEAN Wait,
						 IN ULONG LockKey,
						 IN BOOLEAN CheckForReadOperation,
						 OUT PIO_STATUS_BLOCK IoStatus,
						 IN struct _DEVICE_OBJECT *DeviceObject
						 ) 

{
	PDD_DEVICE devExt=DeviceObject->DeviceExtension;

	DbgMess(("Some FastIo Starts"));

	DbgMess(("Some FastIo Starts"));

	if(FAST_IO_PRESENT(devExt, FastIoCheckIfPossible)){
		return
			GET_PFAST_IO_DISPATCH ->
			FastIoCheckIfPossible(FileObject,
			FileOffset, 
			Length, 
			Wait, 
			LockKey, 
			CheckForReadOperation, 
			IoStatus,
			DeviceObject);
	}
	else
		return FALSE;
}

BOOLEAN  
DDFastIoRead( 
			 IN PFILE_OBJECT FileObject, 
			 IN PLARGE_INTEGER FileOffset, 
			 IN ULONG Length, 
			 IN BOOLEAN Wait, 
			 IN ULONG LockKey, 
			 OUT PVOID Buffer,
			 OUT PIO_STATUS_BLOCK IoStatus, 
			 IN PDEVICE_OBJECT DeviceObject 
			 ) 

{
	PDD_DEVICE devExt=DeviceObject->DeviceExtension;


	DbgMess(("Some FastIo Starts"));

	DbgMess(("Some FastIo Starts"));

	if(FAST_IO_PRESENT(devExt, FastIoRead)) {
		return GET_PFAST_IO_DISPATCH->FastIoRead(
			FileObject,
			FileOffset,
			Length,
			Wait,
			LockKey,
			Buffer,
			IoStatus,
			DeviceObject);
	}
	else
		return FALSE;
}

BOOLEAN  
DDFastIoWrite( 
			  IN PFILE_OBJECT FileObject, 
			  IN PLARGE_INTEGER FileOffset,                             
			  IN ULONG Length, 
			  IN BOOLEAN Wait, 
			  IN ULONG LockKey, 
			  IN PVOID Buffer,
			  OUT PIO_STATUS_BLOCK IoStatus, 
			  IN PDEVICE_OBJECT DeviceObject 
			  ) 

{
	PDD_DEVICE devExt=DeviceObject->DeviceExtension;


	DbgMess(("Some FastIo Starts"));

	DbgMess(("Some FastIo Starts"));

	if(FAST_IO_PRESENT(devExt, FastIoWrite)){ 
		return GET_PFAST_IO_DISPATCH->FastIoWrite(
			FileObject,
			FileOffset,
			Length,
			Wait,
			LockKey,
			Buffer,
			IoStatus,
			DeviceObject);
	}
	else
		return FALSE;
}

BOOLEAN  
DDFastIoQueryBasicInfo( 
					   IN PFILE_OBJECT FileObject, 
					   IN BOOLEAN Wait, 
					   OUT PFILE_BASIC_INFORMATION Buffer,
					   OUT PIO_STATUS_BLOCK IoStatus, 
					   IN PDEVICE_OBJECT DeviceObject 
					   ) 

{
	PDD_DEVICE devExt=DeviceObject->DeviceExtension;


	DbgMess(("Some FastIo Starts"));

	DbgMess(("Some FastIo Starts"));

	if(FAST_IO_PRESENT(devExt, FastIoQueryBasicInfo)){
		return GET_PFAST_IO_DISPATCH->FastIoQueryBasicInfo(
			FileObject,
			Wait,
			Buffer,
			IoStatus,
			DeviceObject);
	}
	else
		return FALSE;
}

BOOLEAN  
DDFastIoQueryStandardInfo( 
						  IN PFILE_OBJECT FileObject, 
						  IN BOOLEAN Wait, 
						  OUT PFILE_STANDARD_INFORMATION Buffer,
						  OUT PIO_STATUS_BLOCK IoStatus, 
						  IN PDEVICE_OBJECT DeviceObject 
						  ) 

{
	PDD_DEVICE devExt=DeviceObject->DeviceExtension;

	DbgMess(("Some FastIo Starts"));

	DbgMess(("Some FastIo Starts"));

	if(FAST_IO_PRESENT(devExt, FastIoQueryStandardInfo)){
		return GET_PFAST_IO_DISPATCH->FastIoQueryStandardInfo(
			FileObject,
			Wait,
			Buffer,
			IoStatus,
			DeviceObject);
	}
	else
		return FALSE;
}

BOOLEAN  
DDFastIoLock( 
			 IN PFILE_OBJECT FileObject, 
			 IN PLARGE_INTEGER FileOffset,
			 IN PLARGE_INTEGER Length, 
			 PEPROCESS ProcessId, 
			 ULONG Key,
			 BOOLEAN FailImmediately, 
			 BOOLEAN ExclusiveLock,
			 OUT PIO_STATUS_BLOCK IoStatus, 
			 IN PDEVICE_OBJECT DeviceObject
			 ) 

{
	PDD_DEVICE devExt=DeviceObject->DeviceExtension;

	DbgMess(("Some FastIo Starts"));

	DbgMess(("Some FastIo Starts"));

	if(FAST_IO_PRESENT(devExt, FastIoLock)){
		return GET_PFAST_IO_DISPATCH->FastIoLock(
			FileObject,
			FileOffset,
			Length,
			ProcessId,
			Key,
			FailImmediately,
			ExclusiveLock,
			IoStatus,
			DeviceObject);
	}
	else
		return FALSE;
}

BOOLEAN  
DDFastIoUnlockSingle( 
					 IN PFILE_OBJECT FileObject, 
					 IN PLARGE_INTEGER FileOffset,
					 IN PLARGE_INTEGER Length, 
					 PEPROCESS ProcessId, 
					 ULONG Key,
					 OUT PIO_STATUS_BLOCK IoStatus, 
					 IN PDEVICE_OBJECT DeviceObject 
					 ) 


{
	PDD_DEVICE devExt=DeviceObject->DeviceExtension;

	DbgMess(("Some FastIo Starts"));

	DbgMess(("Some FastIo Starts"));

	if(FAST_IO_PRESENT(devExt, FastIoUnlockSingle)){
		return GET_PFAST_IO_DISPATCH->FastIoUnlockSingle(
			FileObject,
			FileOffset,
			Length,
			ProcessId,
			Key,
			IoStatus,
			DeviceObject);
	}
	else
		return FALSE;
}

BOOLEAN  
DDFastIoUnlockAll( 
				  IN PFILE_OBJECT FileObject, 
				  PEPROCESS ProcessId,
				  OUT PIO_STATUS_BLOCK IoStatus, 
				  IN PDEVICE_OBJECT DeviceObject 
				  ) 

{
	PDD_DEVICE devExt=DeviceObject->DeviceExtension;

	DbgMess(("Some FastIo Starts"));

	DbgMess(("Some FastIo Starts"));

	if(FAST_IO_PRESENT(devExt, FastIoUnlockAll)){
		return GET_PFAST_IO_DISPATCH->FastIoUnlockAll(
			FileObject,
			ProcessId,
			IoStatus,
			DeviceObject);
	}
	else
		return FALSE;
}

BOOLEAN  
DDFastIoUnlockAllByKey( 
					   IN PFILE_OBJECT FileObject, 
					   PEPROCESS ProcessId, ULONG Key,
					   OUT PIO_STATUS_BLOCK IoStatus, 
					   IN PDEVICE_OBJECT DeviceObject 
					   ) 
{
	PDD_DEVICE devExt=DeviceObject->DeviceExtension;

	DbgMess(("Some FastIo Starts"));

	if(FAST_IO_PRESENT(devExt, FastIoUnlockAllByKey)){
		return GET_PFAST_IO_DISPATCH->FastIoUnlockAllByKey(
			FileObject,
			ProcessId,
			Key,
			IoStatus,
			DeviceObject);
	}
	else
		return FALSE;
}

//
//BOOLEAN  
//DDFastIoDeviceControl( 
//    IN PFILE_OBJECT FileObject, 
//    IN BOOLEAN Wait,
//    IN PVOID InputBuffer, 
//    IN ULONG InputBufferLength, 
//    OUT PVOID OutbufBuffer, 
//    IN ULONG OutputBufferLength, 
//    IN ULONG IoControlCode,
//    OUT PIO_STATUS_BLOCK IoStatus, 
//    IN PDEVICE_OBJECT DeviceObject 
//    ) 
//{
//		PDD_DEVICE devExt=DeviceObject->DeviceExtension;

//DbgMess(("Some FastIo Starts"));

//if(FAST_IO_PRESENT(devExt, m)){
//	return GET_PFAST_IO_DISPATCH->FastIo
//		//}
//}

VOID     
DDFastIoAcquireFile( 
					PFILE_OBJECT FileObject 
					) 
{
	GET_PFAST_IO_DISPATCH2->AcquireFileForNtCreateSection( FileObject);
}


VOID     
DDFastIoReleaseFile(
					PFILE_OBJECT FileObject 
					) 
{
	GET_PFAST_IO_DISPATCH2->ReleaseFileForNtCreateSection(FileObject);
}

VOID     
DDFastIoDetachDevice( 
					 PDEVICE_OBJECT SourceDevice, 
					 PDEVICE_OBJECT TargetDevice 
					 ) 
{
	ULONG i;
	for (i = 0; i < MAX_ATTACHED_DEVICES_COUNT; ++i) 
	{
		DbgMess(("Some FastIo Starts"));

		if (AttachedDevices[i] == SourceDevice) 
		{
			IoDetachDevice(TargetDevice);
			IoDeleteDevice(SourceDevice);
			AttachedDevices[i] = NULL;
			return;
		}
	}

	((PDD_DEVICE)SourceDevice->DeviceExtension)->FileSystem->DriverObject->FastIoDispatch->FastIoDetachDevice(
		SourceDevice, TargetDevice);

}


//
// These are new NT 4.0 Fast I/O calls
//
BOOLEAN  
DDFastIoQueryNetworkOpenInfo(
							 IN PFILE_OBJECT FileObject,
							 IN BOOLEAN Wait, 
							 OUT struct _FILE_NETWORK_OPEN_INFORMATION *Buffer,
							 OUT struct _IO_STATUS_BLOCK *IoStatus, 
							 IN PDEVICE_OBJECT DeviceObject 
							 ) 
{
	PDD_DEVICE devExt=DeviceObject->DeviceExtension;

	DbgMess(("Some FastIo Starts"));

	DbgMess(("Some FastIo Starts"));

	DbgMess(("Some FastIo Starts"));

	if(FAST_IO_PRESENT(devExt, FastIoQueryNetworkOpenInfo)){
		return GET_PFAST_IO_DISPATCH->FastIoQueryNetworkOpenInfo(
			FileObject,
			Wait,
			Buffer,
			IoStatus,
			DeviceObject);
	}
	else
		return FALSE;
}

NTSTATUS 
DDFastIoAcquireForModWrite( 
						   IN PFILE_OBJECT FileObject,
						   IN PLARGE_INTEGER EndingOffset, 
						   OUT struct _ERESOURCE **ResourceToRelease,
						   IN PDEVICE_OBJECT DeviceObject 
						   ) 
{
	PDD_DEVICE devExt=DeviceObject->DeviceExtension;

	DbgMess(("Some FastIo Starts"));

	DbgMess(("Some FastIo Starts"));

	if(FAST_IO_PRESENT(devExt, AcquireForModWrite)){
		return GET_PFAST_IO_DISPATCH->AcquireForModWrite( 
			FileObject,
			EndingOffset, 
			ResourceToRelease,
			DeviceObject );
	}
	else
		return STATUS_NOT_IMPLEMENTED;
}

BOOLEAN  
DDFastIoMdlRead( 
				IN PFILE_OBJECT FileObject,
				IN PLARGE_INTEGER FileOffset, 
				IN ULONG Length,
				IN ULONG LockKey, 
				OUT PMDL *MdlChain, 
				OUT PIO_STATUS_BLOCK IoStatus,
				IN PDEVICE_OBJECT DeviceObject 
				) 
{
	PDD_DEVICE devExt=DeviceObject->DeviceExtension;

	DbgMess(("Some FastIo Starts"));

	DbgMess(("Some FastIo Starts"));

	if(FAST_IO_PRESENT(devExt, MdlRead)){
		return GET_PFAST_IO_DISPATCH->MdlRead( 
			FileObject,
			FileOffset, 
			Length,
			LockKey, 
			MdlChain, 
			IoStatus,
			DeviceObject 
			);
	}
	else
		return FALSE;
}

BOOLEAN  
DDFastIoMdlReadComplete( 
						IN PFILE_OBJECT FileObject,
						IN PMDL MdlChain, 
						IN PDEVICE_OBJECT DeviceObject 
						) 
{
	PDD_DEVICE devExt=DeviceObject->DeviceExtension;

	DbgMess(("Some FastIo Starts"));

	DbgMess(("Some FastIo Starts"));

	if(FAST_IO_PRESENT(devExt, MdlReadComplete)){
		return GET_PFAST_IO_DISPATCH->MdlReadComplete( 
			FileObject,
			MdlChain, 
			DeviceObject 
			);
	}
	else
		return FALSE;
}

BOOLEAN  
DDFastIoPrepareMdlWrite( 
						IN PFILE_OBJECT FileObject,
						IN PLARGE_INTEGER FileOffset, 
						IN ULONG Length, 
						IN ULONG LockKey,
						OUT PMDL *MdlChain, 
						OUT PIO_STATUS_BLOCK IoStatus,
						IN PDEVICE_OBJECT DeviceObject
						) 
{
	PDD_DEVICE devExt=DeviceObject->DeviceExtension;

	DbgMess(("Some FastIo Starts"));

	DbgMess(("Some FastIo Starts"));

	if(FAST_IO_PRESENT(devExt, PrepareMdlWrite)){
		return GET_PFAST_IO_DISPATCH->PrepareMdlWrite( 
			FileObject,
			FileOffset, 
			Length, 
			LockKey,
			MdlChain, 
			IoStatus,
			DeviceObject
			) ;
	}
	else
		return FALSE;
}

BOOLEAN  
DDFastIoMdlWriteComplete( 
						 IN PFILE_OBJECT FileObject,
						 IN PLARGE_INTEGER FileOffset, 
						 IN PMDL MdlChain,
						 IN PDEVICE_OBJECT DeviceObject 
						 ) 
{
	PDD_DEVICE devExt=DeviceObject->DeviceExtension;

	DbgMess(("Some FastIo Starts"));

	DbgMess(("Some FastIo Starts"));

	if(FAST_IO_PRESENT(devExt, MdlWriteComplete)){
		return GET_PFAST_IO_DISPATCH->MdlWriteComplete( 
			FileObject,
			FileOffset, 
			MdlChain,
			DeviceObject 
			);
	}
	else
		return FALSE;
}

BOOLEAN  
DDFastIoReadCompressed( 
					   IN PFILE_OBJECT FileObject,
					   IN PLARGE_INTEGER FileOffset, 
					   IN ULONG Length,
					   IN ULONG LockKey, 
					   OUT PVOID Buffer, 
					   OUT PMDL *MdlChain,
					   OUT PIO_STATUS_BLOCK IoStatus,
					   OUT struct _COMPRESSED_DATA_INFO *CompressedDataInfo,
					   IN ULONG CompressedDataInfoLength, 
					   IN PDEVICE_OBJECT DeviceObject 
					   ) 
{
	PDD_DEVICE devExt=DeviceObject->DeviceExtension;

	DbgMess(("Some FastIo Starts"));

	DbgMess(("Some FastIo Starts"));

	if(FAST_IO_PRESENT(devExt, FastIoReadCompressed)){
		return GET_PFAST_IO_DISPATCH->FastIoReadCompressed( 
			FileObject,
			FileOffset, 
			Length,
			LockKey, 
			Buffer, 
			MdlChain,
			IoStatus,
			CompressedDataInfo,
			CompressedDataInfoLength, 
			DeviceObject 
			);
	}
	else
		return FALSE;
}

BOOLEAN  
DDFastIoWriteCompressed( 
						IN PFILE_OBJECT FileObject,
						IN PLARGE_INTEGER FileOffset, 
						IN ULONG Length,
						IN ULONG LockKey, 
						IN PVOID Buffer, 
						OUT PMDL *MdlChain,
						OUT PIO_STATUS_BLOCK IoStatus,
						IN struct _COMPRESSED_DATA_INFO *CompressedDataInfo,
						IN ULONG CompressedDataInfoLength, 
						IN PDEVICE_OBJECT DeviceObject 
						) 
{
	PDD_DEVICE devExt=DeviceObject->DeviceExtension;

	DbgMess(("Some FastIo Starts"));

	DbgMess(("Some FastIo Starts"));

	if(FAST_IO_PRESENT(devExt, FastIoWriteCompressed)){
		return GET_PFAST_IO_DISPATCH->FastIoWriteCompressed( 
			FileObject,
			FileOffset, 
			Length,
			LockKey, 
			Buffer, 
			MdlChain,
			IoStatus,
			CompressedDataInfo,
			CompressedDataInfoLength, 
			DeviceObject 
			);
	}
	else
		return FALSE;
}

BOOLEAN  
DDFastIoMdlReadCompleteCompressed( 
								  IN PFILE_OBJECT FileObject,
								  IN PMDL MdlChain, 
								  IN PDEVICE_OBJECT DeviceObject 
								  ) 
{
	PDD_DEVICE devExt=DeviceObject->DeviceExtension;

	DbgMess(("Some FastIo Starts"));

	if(FAST_IO_PRESENT(devExt, MdlReadCompleteCompressed)){
		return GET_PFAST_IO_DISPATCH->MdlReadCompleteCompressed( 
			FileObject,
			MdlChain, 
			DeviceObject 
			);
	}
	else
		return FALSE;
}

BOOLEAN  
DDFastIoMdlWriteCompleteCompressed( 
								   PFILE_OBJECT FileObject,
								   IN PLARGE_INTEGER FileOffset, 
								   IN PMDL MdlChain,
								   IN PDEVICE_OBJECT DeviceObject 
								   ) 
{
	PDD_DEVICE devExt=DeviceObject->DeviceExtension;

	DbgMess(("Some FastIo Starts"));

	if(FAST_IO_PRESENT(devExt, MdlWriteCompleteCompressed)){
		return GET_PFAST_IO_DISPATCH->MdlWriteCompleteCompressed( 
			FileObject,
			FileOffset, 
			MdlChain,
			DeviceObject 
			);
	}
	else
		return FALSE;
}

BOOLEAN 
DDFastIoQueryOpen( 
				  IN struct _IRP *Irp,
				  OUT PFILE_NETWORK_OPEN_INFORMATION NetworkInformation,
				  IN PDEVICE_OBJECT DeviceObject 
				  ) 
{
	PDD_DEVICE devExt=DeviceObject->DeviceExtension;

	DbgMess(("Some FastIo Starts"));

	if(FAST_IO_PRESENT(devExt, FastIoQueryOpen)){
		return GET_PFAST_IO_DISPATCH->FastIoQueryOpen( 
			Irp,
			NetworkInformation,
			DeviceObject 
			) ;
	}
	else
		return FALSE;
}

NTSTATUS 
DDFastIoReleaseForModWrite( 
						   IN PFILE_OBJECT FileObject,
						   IN struct _ERESOURCE *ResourceToRelease, 
						   IN PDEVICE_OBJECT DeviceObject 
						   ) 
{
	PDD_DEVICE devExt=DeviceObject->DeviceExtension;

	DbgMess(("Some FastIo Starts"));

	if(FAST_IO_PRESENT(devExt, ReleaseForModWrite)){
		return GET_PFAST_IO_DISPATCH->ReleaseForModWrite( 
			FileObject,
			ResourceToRelease, 
			DeviceObject 
			);
	}
	else
		return STATUS_NOT_IMPLEMENTED;
}

NTSTATUS
DDFastIoAcquireForCcFlush( 
						  IN PFILE_OBJECT FileObject,
						  IN PDEVICE_OBJECT DeviceObject 
						  ) 
{
	PDD_DEVICE devExt=DeviceObject->DeviceExtension;

	DbgMess(("Some FastIo Starts"));

	if(FAST_IO_PRESENT(devExt, AcquireForCcFlush)){
		return GET_PFAST_IO_DISPATCH->AcquireForCcFlush( 
			FileObject,
			DeviceObject 
			);
	}
	else
		return STATUS_NOT_IMPLEMENTED;
}

NTSTATUS
DDFastIoReleaseForCcFlush( 
						  IN PFILE_OBJECT FileObject,
						  IN PDEVICE_OBJECT DeviceObject 
						  ) 
{
	PDD_DEVICE devExt=DeviceObject->DeviceExtension;

	DbgMess(("Some FastIo Starts"));

	if(FAST_IO_PRESENT(devExt, ReleaseForCcFlush)){
		return GET_PFAST_IO_DISPATCH->ReleaseForCcFlush( 
			FileObject,
			DeviceObject 
			);
	}
	else
		return STATUS_NOT_IMPLEMENTED;
}